
系列:30 天打造企業級 PLM|面向:前端
單元測試全綠,使用者一點就炸。因為單元測試的世界裡沒有 antd 的動畫、沒有 SSE 的斷線、沒有「登入後語系切換觸發 reload」。企業系統的信心來源必須是真的用瀏覽器把業務動線跑過一遍。Mini-PLM 的 E2E 建在 Playwright 上,32 個 spec 分三個模組(admin / form / item),今天講組織方式,以及那些只有 E2E 才抓得到的坑。
在以前 Oracle Agile PLM 的時代,企業級端對端自動化測試是一大痛點:
StaleElementReferenceException 或時序逾時,維護測試腳本的時間比寫功能還長。Mini-PLM 採用現代 Playwright 自動化測試框架,利用其原生 Auto-waiting、強大選擇器與完整的 Headless 執行能力,建立起一套高穩定度的 E2E 防護網。
JWT 存在 zustand in-memory(Day 6),Playwright 的 storageState 存不到它,所以走自訂 fixture(Auth Fixture 實碼註解):
/**
* Mini-PLM 的 JWT 存於 zustand in-memory state(非 localStorage / cookie),
* 因此 storageState 無法保存登入狀態 — 改採每個 worker 各自登入一次的 fixture 機制。
* - jwt:worker scope,整個 worker 共享同一 token
* - api:APIRequestContext,已注入 Authorization header
* - authedPage:已自動登入的 page
*/
jwt fixture 用了一個聰明的招:開一個真的登入頁,攔截第一個帶 Authorization header 的 request 把 token 抓出來。不逆向登入 API 的實作,UI 怎麼登入就怎麼拿。api fixture 讓測試能直接打 API 做前置資料與驗證,UI 操作留給真正要測 UI 的部分。
External Lookup 相關測試需要人事系統,用 Day 10 的 mock-lookup-server.ps1 頂上。E2E 測的是我們的系統,外部系統的不穩定不該讓測試變紅。mock 回應固定測資,測試才可重複。
in-memory JWT 的另一個後果:page.goto() 整頁重載會把登入狀態洗掉。導航一律走 SPA 內部跳轉(utils/paths.ts 實碼):
/** SPA 內部跳轉,不觸發 page reload,避免 in-memory JWT 失效。 */
export async function navigateInApp(page: Page, path: string) {
await page.evaluate((p) => {
window.history.pushState({}, "", p);
window.dispatchEvent(new PopStateEvent("popstate"));
}, path);
}
路由集中在 ROUTES 常數,vite base 或 context path 改了只動一處。
這批坑全部來自實戰,包含寫本系列截圖腳本時現場重演的幾個:
isVisible() 不等待,元件還在動畫中就回 false,一律 waitFor
Escape 再點按鈕name: /登\s*入/
waitForLoadState("networkidle") 等到逾時。給它短 timeout 並 catch,或改等具體元素keyword=contains 語意下,260 筆資料抽查「-1」會誤中「-10」到「-199」。斷言要抽不可能是其他值子字串的樣本,例如序號最大值第 8 條值得展開,它是「測試比產品更容易靜默壞掉」的典型:測試碼沒有測試。對策是讓 fixture 的每一步都有斷言(登入後必須看得到主版面),以及定期讓測試失敗一次,改壞一個東西看測試會不會紅,驗證測試還活著。
fixture 解決認證與資料前置(worker 級共享攤平成本),mock 隔離外部不穩定,選擇器與等待策略對抗元件庫的 DOM 現實。E2E 是升級(Day 18)、重構、與每一次上線的安全網,這筆投資在 Day 30 的建議清單裡排前三。明日 Day 21:壓測與效能調校,250 個併發使用者下,誰先倒?